using System.Collections.Generic;
using DotNetOpenAuth.AspNet;
using Microsoft.Web.WebPages.OAuth;

namespace Quintsys.Core.Services
{
    public interface IOAuthWebSecurity
    {
        /// <summary>
        ///     Gets the registered client data.
        /// </summary>
        /// <value>
        ///     The registered client data.
        /// </value>
        ICollection<AuthenticationClientData> RegisteredClientData { get; }

        /// <summary>
        ///     Returns the user ID for the specified OAuth or OpenID provider and provider user ID.
        /// </summary>
        /// <returns>
        ///     The user ID, or null if there is no user ID associated with the OAuth or Open ID provider user ID.
        /// </returns>
        /// <param name="providerName">The provider name.</param>
        /// <param name="providerUserId">The user ID for the specified provider.</param>
        string GetUserName(string providerName, string providerUserId);

        /// <summary>
        ///     Determines whether [has local account] [the specified user id].
        /// </summary>
        /// <param name="userId">The user id.</param>
        /// <returns>
        ///     <c>true</c> if [has local account] [the specified user id]; otherwise, <c>false</c>.
        /// </returns>
        bool HasLocalAccount(int userId);

        /// <summary>
        ///     Gets the account or accounts that are associated using the specified user name.
        /// </summary>
        /// <returns>
        ///     The collection of accounts.
        /// </returns>
        /// <param name="userName">The user name.</param>
        ICollection<OAuthAccount> GetAccountsFromUserName(string userName);

        /// <summary>
        ///     Deletes the specified membership account.
        /// </summary>
        /// <returns>
        ///     true if the account was deleted, or false if it was not.
        /// </returns>
        /// <param name="providerName">The provider name.</param>
        /// <param name="providerUserId">The user ID for the specified provider.</param>
        bool DeleteAccount(string providerName, string providerUserId);

        /// <summary>
        ///     Verifies the authentication.
        /// </summary>
        /// <param name="returnUrl">The return URL.</param>
        /// <returns></returns>
        AuthenticationResult VerifyAuthentication(string returnUrl);

        /// <summary>
        ///     Logs the user in.
        /// </summary>
        /// <returns>
        ///     true if login was successful; otherwise, false.
        /// </returns>
        /// <param name="providerName">The provider name.</param>
        /// <param name="providerUserId">The user ID for the specified provider.</param>
        /// <param name="createPersistentCookie">true to create a persistent cookie so that the login information is saved across browser sessions; otherwise, false.</param>
        bool Login(string providerName, string providerUserId, bool createPersistentCookie);

        /// <summary>
        ///     Creates or updates the account using the specified provider and user ID for the provider ID and associate the new account with the specified user name.
        /// </summary>
        /// <param name="providerName">The provider name.</param>
        /// <param name="providerUserId">The user ID for the specified provider.</param>
        /// <param name="userName">The name of the user.</param>
        void CreateOrUpdateAccount(string providerName, string providerUserId, string userName);

        /// <summary>
        ///     Serializes the provider user id.
        /// </summary>
        /// <param name="providerName">Name of the provider.</param>
        /// <param name="providerUserId">The provider user id.</param>
        /// <returns></returns>
        string SerializeProviderUserId(string providerName, string providerUserId);

        /// <summary>
        ///     Gets the OAuth client data.
        /// </summary>
        /// <param name="providerName">Name of the provider.</param>
        /// <returns></returns>
        AuthenticationClientData GetOAuthClientData(string providerName);

        /// <summary>
        ///     Tries the deserialize provider user id.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="providerName">Name of the provider.</param>
        /// <param name="providerUserId">The provider user id.</param>
        /// <returns></returns>
        bool TryDeserializeProviderUserId(string data, out string providerName, out string providerUserId);

        /// <summary>
        ///     Requests the specified provider to start the authentication by directing users to an external website, and directs the provider to redirect the user to the specified URL when authentication is successful.
        /// </summary>
        /// <param name="provider">The OAuth provider.</param>
        /// <param name="returnUrl">The URL to return to when authentication is successful.</param>
        void RequestAuthentication(string provider, string returnUrl);
    }

    public class OAuthWebSecurityWrapper : IOAuthWebSecurity
    {
        /// <summary>
        ///     Returns the user ID for the specified OAuth or OpenID provider and provider user ID.
        /// </summary>
        /// <param name="providerName">The provider name.</param>
        /// <param name="providerUserId">The user ID for the specified provider.</param>
        /// <returns>
        ///     The user ID, or null if there is no user ID associated with the OAuth or Open ID provider user ID.
        /// </returns>
        public string GetUserName(string providerName, string providerUserId)
        {
            return OAuthWebSecurity.GetUserName(providerName, providerUserId);
        }

        /// <summary>
        ///     Determines whether [has local account] [the specified user id].
        /// </summary>
        /// <param name="userId">The user id.</param>
        /// <returns>
        ///     <c>true</c> if [has local account] [the specified user id]; otherwise, <c>false</c>.
        /// </returns>
        public bool HasLocalAccount(int userId)
        {
            return OAuthWebSecurity.HasLocalAccount(userId);
        }

        /// <summary>
        ///     Gets the account or accounts that are associated using the specified user name.
        /// </summary>
        /// <param name="userName">The user name.</param>
        /// <returns>
        ///     The collection of accounts.
        /// </returns>
        public ICollection<OAuthAccount> GetAccountsFromUserName(string userName)
        {
            return OAuthWebSecurity.GetAccountsFromUserName(userName);
        }

        /// <summary>
        ///     Deletes the specified membership account.
        /// </summary>
        /// <param name="providerName">The provider name.</param>
        /// <param name="providerUserId">The user ID for the specified provider.</param>
        /// <returns>
        ///     true if the account was deleted, or false if it was not.
        /// </returns>
        public bool DeleteAccount(string providerName, string providerUserId)
        {
            return OAuthWebSecurity.DeleteAccount(providerName, providerUserId);
        }

        /// <summary>
        ///     Verifies the authentication.
        /// </summary>
        /// <param name="returnUrl">The return URL.</param>
        /// <returns></returns>
        public AuthenticationResult VerifyAuthentication(string returnUrl)
        {
            return OAuthWebSecurity.VerifyAuthentication(returnUrl);
        }

        /// <summary>
        ///     Logs the user in.
        /// </summary>
        /// <param name="providerName">The provider name.</param>
        /// <param name="providerUserId">The user ID for the specified provider.</param>
        /// <param name="createPersistentCookie">true to create a persistent cookie so that the login information is saved across browser sessions; otherwise, false.</param>
        /// <returns>
        ///     true if login was successful; otherwise, false.
        /// </returns>
        public bool Login(string providerName, string providerUserId, bool createPersistentCookie)
        {
            return OAuthWebSecurity.Login(providerName, providerUserId, createPersistentCookie);
        }

        /// <summary>
        ///     Creates or updates the account using the specified provider and user ID for the provider ID and associate the new account with the specified user name.
        /// </summary>
        /// <param name="providerName">The provider name.</param>
        /// <param name="providerUserId">The user ID for the specified provider.</param>
        /// <param name="userName">The name of the user.</param>
        public void CreateOrUpdateAccount(string providerName, string providerUserId, string userName)
        {
            OAuthWebSecurity.CreateOrUpdateAccount(providerName, providerUserId, userName);
        }

        /// <summary>
        ///     Serializes the provider user id.
        /// </summary>
        /// <param name="providerName">Name of the provider.</param>
        /// <param name="providerUserId">The provider user id.</param>
        /// <returns></returns>
        public string SerializeProviderUserId(string providerName, string providerUserId)
        {
            return OAuthWebSecurity.SerializeProviderUserId(providerName, providerUserId);
        }

        /// <summary>
        ///     Gets the OAuth client data.
        /// </summary>
        /// <param name="providerName">Name of the provider.</param>
        /// <returns></returns>
        public AuthenticationClientData GetOAuthClientData(string providerName)
        {
            return OAuthWebSecurity.GetOAuthClientData(providerName);
        }

        /// <summary>
        ///     Tries the deserialize provider user id.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="providerName">Name of the provider.</param>
        /// <param name="providerUserId">The provider user id.</param>
        /// <returns></returns>
        public bool TryDeserializeProviderUserId(string data, out string providerName, out string providerUserId)
        {
            return OAuthWebSecurity.TryDeserializeProviderUserId(data, out providerName, out providerUserId);
        }

        /// <summary>
        ///     Gets the registered client data.
        /// </summary>
        /// <value>
        ///     The registered client data.
        /// </value>
        public ICollection<AuthenticationClientData> RegisteredClientData
        {
            get { return OAuthWebSecurity.RegisteredClientData; }
        }

        /// <summary>
        ///     Requests the specified provider to start the authentication by directing users to an external website, and directs the provider to redirect the user to the specified URL when authentication is successful.
        /// </summary>
        /// <param name="provider">The OAuth provider.</param>
        /// <param name="returnUrl">The URL to return to when authentication is successful.</param>
        public void RequestAuthentication(string provider, string returnUrl)
        {
            OAuthWebSecurity.RequestAuthentication(provider, returnUrl);
        }
    }
}